package business.playgameForm_Evt;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.JToggleButton;
import javax.swing.Timer;

import presentation.menuForm_UI.MenuForm_UI;
import presentation.playgameForm_UI.GameMode_UI;
import service.Service;

public class GameMode_Evt {

	// =======================================================
	// Variable
	// =======================================================
	private JFrame		frame;
	private Service		ser					= new Service();
	private PlaySound	sound				= new PlaySound();

	public int			point				= 0;
	public int			gameMode_point		= 0;
	public int			gameMode_score		= 0;
	public int			gameMode_highScore	= 0;
	public int			gameMode_target		= 50;
	public int			gameMode_time		= 120;
	public int			gameMode_level		= 0;
	public String		gameMode_textTemp	= "";

	public int			gameMode			= 0;

	ArrayList<String>	list				= ser.getWordWithLength(11);

	private JLabel		lbHighScore;
	private JLabel		lbScore;
	private Timer		timer;
	private Timer		timer1;

	private Color[]		listColor			= new Color[11];

	private int			counter				= 0;
	private int			countTime			= 0;
	private int			counter1			= 0;
	private int			countTime1			= 0;

	private int			maxLength			= 0;
	private String		bestWord			= "";
	private int			maxPoint			= 0;
	private double		charPerMin			= 0;
	private double		avgOfLength			= 0;
	private int			allTime				= 0;
	private int			wordFound			= 0;
	private int			maxLevel			= 0;

	private int			bonus				= 0;

	// =======================================================
	// End Variable
	// =======================================================
	public GameMode_Evt(JFrame frame, JLabel lbHighScore, JLabel lbScore) {
		loadGameStatics();
		this.frame = frame;
		this.lbHighScore = lbHighScore;
		this.lbScore = lbScore;

		gameMode_highScore = loadHighScore();

		timer = new Timer(100, highScoreFlashing);
		timer1 = new Timer(100, scoreFlashing);

		for (int i = 0; i < listColor.length; i += 2) {
			listColor[i] = Color.red;
			if (i > 0) {
				listColor[i - 1] = Color.black;
			}
		}

	}

	public GameMode_Evt() {
	}

	private ActionListener	highScoreFlashing	= new ActionListener() {

													@Override
													public void actionPerformed(ActionEvent e) {
														countTime++;
														if (counter == 11) {
															counter = 0;
														}
														lbHighScore.setForeground(listColor[counter++]);

														if (countTime == 10) {
															countTime = 0;
															lbHighScore.setForeground(Color.black);
															timer.stop();

														}
													}
												};
	private ActionListener	scoreFlashing		= new ActionListener() {

													@Override
													public void actionPerformed(ActionEvent e) {
														countTime1++;
														if (counter1 == 11) {
															counter1 = 0;
														}
														lbScore.setForeground(listColor[counter1++]);

														if (countTime1 == 10) {
															countTime1 = 0;
															lbScore.setForeground(Color.black);
															timer1.stop();

														}
													}
												};

	/**
	 * this method will show main menu and also it close your playing windows.
	 * And it will not save anything about your score and your level ... all of
	 * them will not be saved, be care full with this choice
	 */
	public void showMainMenu() {
		frame.setVisible(false);
		MenuForm_UI.frame.setVisible(true);
		System.gc();
	}

	/**
	 * This method will text from your input toggle button and append it with
	 * your label text
	 * 
	 * @param toggleBt
	 * @param label
	 */
	public void setTextToLabel(JToggleButton toggleBt, JLabel label) {
		label.setText(label.getText() + toggleBt.getText());
	}

	/**
	 * This method will check whether your input word is exist in dictionary or
	 * not.
	 * 
	 * @param word
	 * @return boolean value
	 */
	public boolean findWord(String word) {
		return ser.isExistWord(word);
	}

	/**
	 * This method is one of the most important method in game. It will
	 * Calculate your point with your word length, and set that point to your
	 * lbPoint and also it will add your point to your current score, and
	 * increase your progress bar value and if your score is larger than your
	 * record it will set new high score into your label highScore and write it
	 * into file for next time use
	 * 
	 * @param word
	 * @param lbPoint
	 * @param lbScore
	 * @param progress
	 * @param lbHighScore
	 */
	public int	nextPoint	= 2;

	public void setPoint(String word, JLabel lbPoint, JLabel lbScore, JProgressBar progress, JLabel lbHighScore) {
		int point = 3;

		if (word.length() != 2) {

			for (int n = 3; n <= word.length(); n++) {
				point += nextPoint * n;
			}
		}
		point += this.bonus;
		this.point = point;

		lbPoint.setText(Integer.parseInt(lbPoint.getText()) + point + "");

		gameMode_point += point;
		gameMode_score += point;

		if (gameMode_score > gameMode_highScore) {
			highScoreSound();
			gameMode_highScore = gameMode_score;
			if (gameMode != GameMode_UI.PRACTICE_MODE) {
				highScoreSound();
				updateHighScore(gameMode_highScore = gameMode_score);
			}
			lbHighScore.setText("High score: " + gameMode_highScore);
			timer.start();
		}
		progress.setValue(gameMode_point);
		progress.setStringPainted(true);
		progress.setBorderPainted(true);
		lbScore.setText("Score: " + gameMode_score + "");
		this.bonus = 0;
		timer1.start();

	}

	public void setBonusPoint(int bonus) {
		this.bonus = bonus;
	}

	public int maxPointOfWord(String word) {
		int point = 3;

		if (word.length() != 2) {
			for (int n = 3; n <= word.length(); n++) {
				point += nextPoint * n;
			}
		}
		return point;
	}

	/**
	 * This method will convert your time in seconds into format m:ss. Example
	 * 2:00, and set it into your input label
	 * 
	 * @param time
	 * @param label
	 */
	public void setTime(int time, JLabel label) {
		label.setText("Time: " + ser.timeFormated(time));
	}

	/**
	 * This method is one of important method. It will get Available word from
	 * dictionary and then append it together and return a text that contains
	 * four available word with length per word is equal 14
	 * 
	 * @return AvailableWord
	 */
	public String getAvailabelWord() {
		String text = "";
		Random rd = new Random();

		for (int i = 0; i < 4; i++) {
			text += list.get(rd.nextInt(list.size() - 1));
		}
		return text + "AIUE";
	}

	/**
	 * This method will play sound when you found a word or not
	 * 
	 * @param found
	 */
	public void playSound(boolean found) {
		if (found) {
			try {
				sound.soundMode = PlaySound.WORD_FOUND;
				Thread thread = new Thread(sound);
				thread.start();
			} catch (Exception ex) {
			}
		}
		else {
			try {
				sound.soundMode = PlaySound.WORD_NOT_FOUND;
				Thread thread = new Thread(sound);
				thread.start();
			} catch (Exception ex) {
			}
		}
	}

	/**
	 * This method will play clocking sound tick tock, tick tock
	 */
	public void clockTickingSound() {
		try {
			sound.soundMode = PlaySound.CLOCK_TICKING;
			Thread thread = new Thread(sound);
			thread.start();
		} catch (Exception ex) {
		}
	}

	/**
	 * This method will play breaks high score sound
	 */
	public void highScoreSound() {
		try {
			sound.soundMode = PlaySound.HIGH_SCORE;
			Thread thread = new Thread(sound);
			Thread.sleep(50);
			thread.start();
		} catch (Exception ex) {
		}
	}

	/**
	 * This will return a list of key in Integer value.
	 * 
	 * @return a list of key
	 */
	public int[] listControlKeys() {
		return ser.gameControls();
	}

	/**
	 * This method will return a list option of your last saved game to continue
	 * playing
	 * 
	 * @return String[]
	 */
	public String[] loadGameSaved() {
		return ser.loadSavedGame();
	}

	/**
	 * This will get your highScore all time from file and return it
	 * 
	 * @return Integer value
	 */
	public int loadHighScore() {
		return ser.highScore();
	}

	/**
	 * This will get time from your file and return it
	 * 
	 * @return Integer value
	 */
	public int loadTime() {
		String[] time = ser.gameStatics();
		return Integer.parseInt(time[3]);
	}

	/**
	 * Load some value from GameStatics.txt file. Such as, maxLength, bestWord,
	 * charPerMin, avgOfLength, allTime
	 */
	private void loadGameStatics() {
		String[] list = ser.gameStatics();
		this.maxLength = Integer.parseInt(list[0]);
		this.bestWord = list[1];
		this.maxPoint = Integer.parseInt(list[2]);
		this.charPerMin = Double.parseDouble(list[3]);
		this.allTime = Integer.parseInt(list[4]);
		this.avgOfLength = Double.parseDouble(list[5]);
		this.wordFound = Integer.parseInt(list[6]);
		this.maxLevel = Integer.parseInt(list[7]);
	}

	/**
	 * This method will update your new highScore into file
	 * 
	 * @param highScore
	 */
	private void updateHighScore(int highScore) {
		ser.updateHighScore(highScore);
	}

	/**
	 * This method will update your gameStatics into file GameStatics.
	 * 
	 * @param maxLength
	 * @param bestWord
	 * @param charPerMin
	 * @param totalTime
	 * @param avgOfLength
	 */
	public void updateGameStatics(int maxLength, String bestWord, int maxPoint, double charPerMin, int totalTime, double avgOfLength, int wordFound, int maxLevel) {
		this.allTime += totalTime;
		this.wordFound += wordFound;
		this.avgOfLength += avgOfLength;
		this.avgOfLength = round(this.avgOfLength / 2, 3);

		if (this.maxLength <= maxLength) {
			this.maxLength = maxLength;
			if (this.maxPoint <= maxPoint) {
				this.maxPoint = maxPoint;
				if (this.maxLevel <= maxLevel) {
					this.maxLevel = maxLevel;
					if (this.charPerMin <= charPerMin) {
						this.charPerMin = charPerMin;
						ser.updateGameStatics(maxLength, bestWord, maxPoint, charPerMin, this.allTime, this.avgOfLength, this.wordFound, maxLevel);
					}
					else if (this.charPerMin > charPerMin) {
						ser.updateGameStatics(maxLength, bestWord, maxPoint, this.charPerMin, this.allTime, this.avgOfLength, this.wordFound, maxLevel);
					}
				}
				else if (this.maxLevel > maxLevel) {
					if (this.charPerMin <= charPerMin) {
						this.charPerMin = charPerMin;
						ser.updateGameStatics(maxLength, bestWord, maxPoint, charPerMin, this.allTime, this.avgOfLength, this.wordFound, this.maxLevel);
					}
					else if (this.charPerMin > charPerMin) {
						ser.updateGameStatics(maxLength, bestWord, maxPoint, this.charPerMin, this.allTime, this.avgOfLength, this.wordFound, this.maxLevel);
					}
				}
			}
			else if (this.maxPoint > maxPoint) {
				if (this.maxLevel <= maxLevel) {
					this.maxLevel = maxLevel;
					if (this.charPerMin <= charPerMin) {
						this.charPerMin = charPerMin;
						ser.updateGameStatics(maxLength, bestWord, this.maxPoint, charPerMin, this.allTime, this.avgOfLength, this.wordFound, maxLevel);
					}
					else if (this.charPerMin > charPerMin) {
						ser.updateGameStatics(maxLength, bestWord, this.maxPoint, this.charPerMin, this.allTime, this.avgOfLength, this.wordFound, maxLevel);
					}
				}
				else if (this.maxLevel > maxLevel) {
					if (this.charPerMin <= charPerMin) {
						this.charPerMin = charPerMin;
						ser.updateGameStatics(maxLength, bestWord, this.maxPoint, charPerMin, this.allTime, this.avgOfLength, this.wordFound, this.maxLevel);
					}
					else if (this.charPerMin > charPerMin) {
						ser.updateGameStatics(maxLength, bestWord, this.maxPoint, this.charPerMin, this.allTime, this.avgOfLength, this.wordFound, this.maxLevel);
					}
				}
			}
		}
		else if (this.maxLength > maxLength) {
			if (this.maxPoint <= maxPoint) {
				this.maxPoint = maxPoint;
				if (this.maxLevel <= maxLevel) {
					this.maxLevel = maxLevel;
					if (this.charPerMin <= charPerMin) {
						this.charPerMin = charPerMin;
						ser.updateGameStatics(this.maxLength, this.bestWord, maxPoint, charPerMin, this.allTime, this.avgOfLength, this.wordFound, maxLevel);
					}
					else if (this.charPerMin > charPerMin) {
						ser.updateGameStatics(this.maxLength, this.bestWord, maxPoint, this.charPerMin, this.allTime, this.avgOfLength, this.wordFound, maxLevel);
					}
				}
				else if (this.maxLevel > maxLevel) {
					if (this.charPerMin <= charPerMin) {
						this.charPerMin = charPerMin;
						ser.updateGameStatics(this.maxLength, this.bestWord, maxPoint, charPerMin, this.allTime, this.avgOfLength, this.wordFound, this.maxLevel);
					}
					else if (this.charPerMin > charPerMin) {
						ser.updateGameStatics(this.maxLength, this.bestWord, maxPoint, this.charPerMin, this.allTime, this.avgOfLength, this.wordFound, this.maxLevel);
					}
				}
			}
			else if (this.maxPoint > maxPoint) {
				if (this.maxLevel <= maxLevel) {
					this.maxLevel = maxLevel;
					if (this.charPerMin <= charPerMin) {
						this.charPerMin = charPerMin;
						ser.updateGameStatics(this.maxLength, this.bestWord, this.maxPoint, charPerMin, this.allTime, this.avgOfLength, this.wordFound, maxLevel);
					}
					else if (this.charPerMin > charPerMin) {
						ser.updateGameStatics(this.maxLength, this.bestWord, this.maxPoint, this.charPerMin, this.allTime, this.avgOfLength, this.wordFound, maxLevel);
					}
				}
				else if (this.maxLevel > maxLevel) {
					if (this.charPerMin <= charPerMin) {
						this.charPerMin = charPerMin;
						ser.updateGameStatics(this.maxLength, this.bestWord, this.maxPoint, charPerMin, this.allTime, this.avgOfLength, this.wordFound, this.maxLevel);
					}
					else if (this.charPerMin > charPerMin) {
						ser.updateGameStatics(this.maxLength, this.bestWord, this.maxPoint, this.charPerMin, this.allTime, this.avgOfLength, this.wordFound, this.maxLevel);
					}
				}
			}
		}
	}

	/**
	 * This method will rounded your input number with your preferred length
	 * 
	 * @param number
	 * @param length
	 * @return rounded number
	 */
	public double round(double number, int length) {

		String numTemp = Double.toString(number);
		int index = numTemp.indexOf('.');
		String subString = numTemp.substring(index, numTemp.length());

		String temp = numTemp.substring(0, index);

		if (index + length > numTemp.length() || subString.length() <= length) {
			return number;
		}

		for (int i = index; i <= index + length; i++) {
			temp += numTemp.charAt(i);
		}

		return Double.parseDouble(temp);
	}

	/**
	 * This method will save your current game state for next time play
	 */
	public void saveGame(int gameMode_level, int gameMode_score, int gameMode_target, int gameMode_point, int gameMode_time, String gameMode_textTemp) {
		ser.saveGame(gameMode_level, gameMode_score, gameMode_target, gameMode_point, gameMode_time, gameMode_textTemp);
	}

	/**
	 * This method will update all variable that need to be updated before save
	 * into your file
	 * 
	 * @param gameMode_level
	 * @param gameMode_score
	 * @param gameMode_target
	 * @param gameMode_point
	 * @param gameMode_time
	 */
	public void updateValueForEventUse(int gameMode_level, int gameMode_score, int gameMode_target, int gameMode_point, int gameMode_time) {
		this.gameMode_level = gameMode_level;
		this.gameMode_score = gameMode_score;
		this.gameMode_target = gameMode_target;
		this.gameMode_point = gameMode_point;
		this.gameMode_time = gameMode_time;
	}

	public void playNextLevelSound() {
		try {
			sound.soundMode = PlaySound.NEXT_LEVEL;
			Thread thread = new Thread(sound);
			thread.start();
		} catch (Exception ex) {
		}

	}

	public String formatTimeEndGame(int time)
	{
		return ser.timeStaticsFormat(time);
	}

	
	public int[] loadKey()
	{
		return ser.gameControls();
	}
}
